﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.Office.Interop.Outlook;
using Outlook.WorkItems.Extension.Controls;
using Outlook.WorkItems.Extension.Manager.TeamProjectManager;
using System.Xml.Linq;
using System.IO;
using Outlook.WorkItems.Extension.Addin.Actions;

namespace Outlook.WorkItems.Extension.Addin.Forms
{
    public partial class WorkItemMappingForm : Form
    {
        private readonly WorkItemType _workItemType;
        private Microsoft.Office.Interop.Outlook.Application _application;
        private readonly OutlookItem _outlookItem;
        private readonly List<WorkItemMapping> _mappingList = new List<WorkItemMapping>();
        private WorkItemMapping _mapping;

        public WorkItem WorkItem
        {
            get
            {
                var workItem = new WorkItem(_workItemType);
                foreach (MappingListViewItem item in listView1.Items)
                {
                    if (!string.IsNullOrEmpty(item.ItemPropertyName) && _outlookItem.ItemProperties[item.ItemPropertyName].Value != null)
                    {
                        if (item.ItemPropertyName == "HTMLBody" && (workItem.Type.FieldDefinitions[item.FieldDefinitionName].FieldType == FieldType.String || workItem.Type.FieldDefinitions[item.FieldDefinitionName].FieldType == FieldType.PlainText))
                        {
                            var filePath = Path.GetTempFileName();
                            _outlookItem.SaveAs(filePath, OlSaveAsType.olTXT);
                            workItem.Fields[item.FieldDefinitionName].Value = File.ReadAllText(filePath);
                        }
                        else if (item.ItemPropertyName == "HTMLBody" && workItem.Type.FieldDefinitions[item.FieldDefinitionName].FieldType == FieldType.Html)
                            workItem.Fields[item.FieldDefinitionName].Value = _outlookItem.Description;
                        else
                            workItem.Fields[item.FieldDefinitionName].Value = _outlookItem.ItemProperties[item.ItemPropertyName].Value;
                    }
                    else if (!string.IsNullOrEmpty(item.StaticValue))
                    {
                        workItem.Fields[item.FieldDefinitionName].Value = item.StaticValue;
                    }
                }
                return workItem;
            }
        }

        public WorkItemMapping WorkItemMapping
        {
            get
            {
                var workItemMapping = new WorkItemMapping
                                          {
                                              WorkItemType = _workItemType.Name,
                                              MappingFields = new List<MappingField>()
                                          };
                foreach (MappingListViewItem mappingListViewItem in listView1.Items)
                {
                    workItemMapping.MappingFields.Add(new MappingField() { MessageFieldName = mappingListViewItem.ItemPropertyName, StaticValue = mappingListViewItem.StaticValue, WiFieldName = mappingListViewItem.FieldDefinitionName });
                }
                return workItemMapping;
            }
        }

        public WorkItemMappingForm()
        {
            InitializeComponent();
        }

        public WorkItemMappingForm(Microsoft.Office.Interop.Outlook.Application application, WorkItemType workItemType, OutlookItem outlookItem)
            : this()
        {
            _workItemType = workItemType;
            _application = application;
            _outlookItem = outlookItem;
        }

        public WorkItemMappingForm(Microsoft.Office.Interop.Outlook.Application application, WorkItemType workItemType, OutlookItem outlookItem, WorkItemMapping mapping)
            : this(application, workItemType, outlookItem)
        {
            _mapping = mapping;
        }

        private void WorkItemMapping_Load(object sender, EventArgs e)
        {
            InitExistingMapping();

            if (_mapping == null)
            {
            listView1.Items.Add(new MappingListViewItem(_workItemType.FieldDefinitions["Title"],
                                                        _outlookItem.ItemProperties["Subject"]));
            }
            else
            {
                foreach (var mappingField in
                _mapping.MappingFields.Where(mappingField => _workItemType.FieldDefinitions.Contains(mappingField.WiFieldName)))
                {
                    if (!string.IsNullOrEmpty(mappingField.MessageFieldName))
                    {
                        var itemProperty = _outlookItem.ItemProperties[mappingField.MessageFieldName];
                        if (itemProperty != null)
                        {
                            listView1.Items.Add(
                                new MappingListViewItem(
                                    _workItemType.FieldDefinitions[mappingField.WiFieldName], itemProperty));
                        }
                    }
                    else if (!string.IsNullOrEmpty(mappingField.StaticValue))
                    {
                        listView1.Items.Add(
                            new MappingListViewItem(
                                _workItemType.FieldDefinitions[mappingField.WiFieldName], null, mappingField.StaticValue));
                    }
                }
            }
            var workItemFieldItems = (from FieldDefinition item in _workItemType.FieldDefinitions
                                      where item.IsEditable
                                      select new WorkItemFieldItem() { FieldDefinition = item }).ToList();
            var propertyItems = (from ItemProperty itemProperty in _outlookItem.ItemProperties
                                 select new MailFieldItem() { ItemProperty = itemProperty }).ToList();



            comboWorkItemField.DataSource = workItemFieldItems;
            comboWorkItemField.DisplayMember = "Name";

            comboItemProperty.DataSource = propertyItems;
            comboItemProperty.DisplayMember = "Name";
        }

        private void InitExistingMapping()
        {
            var filePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\OWIPlugin\\WorkItemMapping.owi";

            if (!File.Exists(filePath))
                return;

            XDocument xdoc = XDocument.Load(filePath);
            XElement rootElement = xdoc.Element("WorkItemMappings");

            if (rootElement == null)
                return;

            foreach (var xElement in rootElement.Elements("WorkItemMapping"))
            {
                var wim = new WorkItemMapping();
                wim.DeserializeWorkItemMapping(xElement);
                openMappingtoolStripSplitButton.DropDownItems.Add(wim.Name, null, LoadMapping_Click);
                _mappingList.Add(wim);
            }
        }

        private void LoadMapping_Click(object sender, EventArgs e)
        {
            var button = sender as ToolStripItem;
            if (button == null)
                return;

            var workItemMapping = _mappingList.Where(m => m.Name == button.Text).FirstOrDefault();

            listView1.Items.Clear();

            if (workItemMapping == null)
                return;

            foreach (var mappingField in
                workItemMapping.MappingFields.Where(mappingField => _workItemType.FieldDefinitions.Contains(mappingField.WiFieldName)))
            {
                if (!string.IsNullOrEmpty(mappingField.MessageFieldName))
                {
                    var itemProperty = _outlookItem.ItemProperties[mappingField.MessageFieldName];
                    if (itemProperty != null)
                    {
                        listView1.Items.Add(
                            new MappingListViewItem(
                                _workItemType.FieldDefinitions[mappingField.WiFieldName], itemProperty));
                    }
                }
                else if (!string.IsNullOrEmpty(mappingField.StaticValue))
                {
                    listView1.Items.Add(
                        new MappingListViewItem(
                            _workItemType.FieldDefinitions[mappingField.WiFieldName], null, mappingField.StaticValue));
                }
            }
        }

        private void btnDefineStaticValue_Click(object sender, EventArgs e)
        {
            var wi = new WorkItem(_workItemType);

            try
            {
                using (var frm = new WorkItemForm(_workItemType.Store, wi))
                {
                    if (frm.ShowDialog() == DialogResult.OK)
                    {
                        foreach (var item in
                            wi.Fields.Cast<Field>().Where(item => item.IsValid && item.IsDirty && item.FieldDefinition.IsEditable))
                        {
                            if (listView1.Items.ContainsKey(item.Name))
                                listView1.Items.RemoveByKey(item.Name);
                            listView1.Items.Add(new MappingListViewItem(item.FieldDefinition, null, item.Value));
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        private void listView1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Delete)
                return;

            foreach (ListViewItem selectedItem in listView1.SelectedItems)
            {
                listView1.Items.Remove(selectedItem);
            }
        }

        private void btnAddMapping_Click(object sender, EventArgs e)
        {
            var fieldDefinition = ((WorkItemFieldItem)comboWorkItemField.SelectedItem).FieldDefinition;
            var itemProperty = ((MailFieldItem)comboItemProperty.SelectedItem).ItemProperty;

            if (listView1.Items.ContainsKey(fieldDefinition.Name))
                listView1.Items.RemoveByKey(fieldDefinition.Name);

            listView1.Items.Add(new MappingListViewItem(fieldDefinition,
                                                itemProperty));
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            var wim = new WorkItemMapping
                          {
                              WorkItemType = _workItemType.Name,
                              MappingFields = new List<MappingField>()
                          };
            foreach (MappingListViewItem mappingListViewItem in listView1.Items)
            {
                wim.MappingFields.Add(new MappingField() { MessageFieldName = mappingListViewItem.ItemPropertyName, StaticValue = mappingListViewItem.StaticValue, WiFieldName = mappingListViewItem.FieldDefinitionName });
            }
            using (var frm = new SaveMappingForm(wim))
            {
                frm.ShowDialog(this);
            }
        }

        private void WorkItemMappingForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult == DialogResult.OK) // && this.validateRequiredFields)
            {
                var mapping = new WorkItemMapping
                          {
                              WorkItemType = _workItemType.Name,
                              MappingFields = new List<MappingField>()
                          };
                foreach (MappingListViewItem mappingListViewItem in listView1.Items)
                {
                    mapping.MappingFields.Add(new MappingField() { MessageFieldName = mappingListViewItem.ItemPropertyName, StaticValue = mappingListViewItem.StaticValue, WiFieldName = mappingListViewItem.FieldDefinitionName });
                }

                WorkItem wi = _workItemType.NewWorkItem();

                foreach (MappingField mf in mapping.MappingFields)
                {
                    if (string.IsNullOrEmpty(mf.MessageFieldName) && string.IsNullOrEmpty(mf.StaticValue))
                    {
                        if (wi.Fields[mf.WiFieldName].IsRequired && wi.Fields[mf.WiFieldName].IsEditable)
                        {
                            e.Cancel = true;
                            MessageBox.Show(string.Format("Work Item Field {0} is required. Define mapping or static value for this field.", mf.WiFieldName));
                            break;
                        }
                    }
                }
            }
        }
    }

    public class MappingListViewItem : ListViewItem
    {
        private readonly FieldDefinition _fieldDefinition;
        private readonly ItemProperty _itemProperty;
        private readonly object _staticValue;

        public MappingListViewItem(FieldDefinition fieldDefinition, ItemProperty itemProperty, object staticValue = null)
        {
            Name = fieldDefinition.Name;
            Text = fieldDefinition.Name;
            SubItems.Add(itemProperty != null ? itemProperty.Name : "");
            SubItems.Add(staticValue != null ? staticValue.ToString() : "");
            _fieldDefinition = fieldDefinition;
            _staticValue = staticValue;
            _itemProperty = itemProperty;
        }

        public string FieldDefinitionName { get { return _fieldDefinition.Name; } }
        public string ItemPropertyName { get { return _itemProperty != null ? _itemProperty.Name : ""; } }
        public string StaticValue { get { return _staticValue != null ? _staticValue.ToString() : ""; } }
    }
}
